package cn.lyjuan.android.mylibrary.context;

import android.content.Context;
import android.support.annotation.NonNull;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import cn.lyjuan.base.util.StringUtils;
import io.realm.DynamicRealm;
import io.realm.FieldAttribute;
import io.realm.Realm;
import io.realm.RealmConfiguration;
import io.realm.RealmMigration;
import io.realm.RealmModel;
import io.realm.RealmObjectSchema;
import io.realm.RealmSchema;
import io.realm.annotations.Ignore;
import io.realm.annotations.Index;
import io.realm.annotations.PrimaryKey;
import io.realm.annotations.RealmModule;
import io.realm.annotations.Required;

/**
 * 提供Realm初始化和获取能力
 * Created by chad on 06/11/2017.
 */
public class RealmApplication extends BaseApplication
{
    protected static RealmConfiguration realmConfig;

    @Override
    public void onCreate()
    {
        super.onCreate();

        init(getContext());
    }

    /**
     * 初始化 init
     *
     * @param context
     */
    protected void init(Context context)
    {
        Realm.init(context);

        realmConfig();// 生成 Realm 配置
    }

    public static Realm realm()
    {
        if (null == realmConfig)
            throw new IllegalStateException("realm application not load");
        return Realm.getInstance(realmConfig);
    }

    /**
     * 默认的 Realm 配置
     *
     * @return
     */
    protected RealmConfiguration realmConfig()
    {
        if (null == realmConfig)
        {
            RealmConfiguration.Builder builder = new RealmConfiguration.Builder();
            builder.schemaVersion(realmVersion());// 版本
            if (null != realmMigration())// 升级
                builder.migration(realmMigration());
            if (!StringUtils.isNull(assetFile()))// 使用asset文件提供初始化
                builder.assetFile(assetFile());
            if (null != directory())// realm文件保存目录
                builder.directory(directory());
            if (isDelIfMig())// 需要升级时删除原文件
                builder.deleteRealmIfMigrationNeeded();
            // 添加模块
            builder.modules(new BaseUtilRealmModule(), modules());
            realmConfig = builder.build();
            // 设置为默认配置，使用Realm.getDefaultConfiguration获取此配置
            Realm.setDefaultConfiguration(realmConfig);
        }

        return realmConfig;
    }

    @RealmModule(library = true, allClasses = true)
    public class BaseUtilRealmModule
    {
    }

    /**
     * 当Realm需要升级时，是否简单删除原文件<br />
     * @return
     */
    protected boolean isDelIfMig()
    {
        return false;
    }

    /**
     * 添加模块
     *
     * @return
     */
    protected Object[] modules()
    {
        return null;
    }

    /**
     * realm 文件保存目录
     *
     * @return
     */
    protected File directory()
    {
        return context.getFilesDir();
    }

    /**
     * 从asset目录下拷贝 realm 初始化文件
     *
     * @return
     */
    protected String assetFile()
    {
        return null;
    }

    /**
     * 版本
     *
     * @return
     */
    protected long realmVersion()
    {
        return 0;
    }

    protected List<SubMigration> subMigrations()
    {
        return null;
    }

    /**
     * 升级
     *
     * @return
     */
    protected RealmMigration realmMigration()
    {
        MyRealmMigration mig = new MyRealmMigration();

        mig.addAll(subMigrations());

        return mig;
    }

    /**
     * 全新创建一个Realm Schema
     *
     * @param schema
     * @param c
     */
    public static void createSechem(RealmSchema schema, Class<? extends RealmModel> c)
    {
        String schemaName = c.getSimpleName();
        RealmObjectSchema objectSchema = schema.create(schemaName);
        Field[] fs = c.getDeclaredFields();

        for (Field f : fs)
        {
            int mod = f.getModifiers();
            if (Modifier.isAbstract(mod)) continue;
            if (Modifier.isFinal(mod)) continue;
            if (Modifier.isStatic(mod)) continue;
            if (f.isAnnotationPresent(Ignore.class)) continue;

            List<FieldAttribute> fas = new ArrayList<>();
            if (f.isAnnotationPresent(PrimaryKey.class))
                fas.add(FieldAttribute.PRIMARY_KEY);
            if (f.isAnnotationPresent(Index.class))
                fas.add(FieldAttribute.INDEXED);
            if (f.isAnnotationPresent(Required.class))
                fas.add(FieldAttribute.REQUIRED);

            objectSchema.addField(f.getName(), f.getType(), fas.toArray(new FieldAttribute[fas.size()]));
        }
    }

    public static class MyRealmMigration implements RealmMigration
    {
        private List<SubMigration> list = new ArrayList();

        @Override
        public void migrate(DynamicRealm realm, long from, long to)
        {
            Collections.sort(list);// 按from从小到大排序
            // 升级
            for (SubMigration m : list)
            {
                m.migrate(realm, from, to);// 依次执行升级
            }
        }

        /**
         * 增加升级子项<br />
         * 链式操作
         *
         * @param sub
         * @return
         */
        public MyRealmMigration add(SubMigration sub)
        {
            list.add(sub);
            return this;
        }

        public MyRealmMigration addAll(List<SubMigration> subs)
        {
            if (null != subs && !subs.isEmpty())
                list.addAll(subs);
            return this;
        }
    }

    public static abstract class SubMigration implements Comparable<SubMigration>
    {
        private long from;

        public SubMigration(long from)
        {
            this.from = from;
        }

        public void migrate(DynamicRealm realm, long from, long to)
        {
            if (this.from >= from && this.from < to)
                migrate(realm);
        }

        public abstract void migrate(DynamicRealm realm);

        /**
         * 按from从小到大排序
         *
         * @param o
         * @return
         */
        @Override
        public int compareTo(@NonNull SubMigration o)
        {
            return this.from < o.from ? -1 : 1;
        }
    }
}
